package com.oauth2.client.config;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.RequestToViewNameTranslator;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
@EnableWebMvc // 替换了 <mvc:annotation-driven> 注解
@ComponentScan(basePackages = {"com.oauth2.client.controller" }, 
        useDefaultFilters = false,
		includeFilters = @ComponentScan.Filter({Controller.class,
			RestController.class})
		)
public class WebServletContextConfig implements WebMvcConfigurer {

	@Autowired ObjectMapper objectMapper;
	@Autowired Marshaller marshaller;
	@Autowired Unmarshaller unmarshaller;
	@Autowired SpringValidatorAdapter validator;

	/** 配置消息转换器 */
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		Charset charsetUTF8 = Charset.forName("UTF-8");
		converters.add(new ByteArrayHttpMessageConverter());

		// 字符串转换器
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
		stringHttpMessageConverter.setSupportedMediaTypes(Arrays.asList(
				new MediaType("text", "html", charsetUTF8),
				//new MediaType("application", "json", charsetUTF8),
				new MediaType("application", "x-www-form-urlencoded", charsetUTF8),
				new MediaType("text", "plain", charsetUTF8)));
		
		converters.add(stringHttpMessageConverter);
		converters.add(new FormHttpMessageConverter());
		converters.add(new SourceHttpMessageConverter<>());

		// xml 转换器
		MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
		xmlConverter.setSupportedMediaTypes(Arrays.asList(
				new MediaType("application", "xml", charsetUTF8),
				new MediaType("text", "xml", charsetUTF8)));
		xmlConverter.setMarshaller(this.marshaller);
		xmlConverter.setUnmarshaller(this.unmarshaller);
		converters.add(xmlConverter);

		// json 转换器
		/*
		 * new MediaType("text", "html",charsetUTF8), new
		 * MediaType("application", "json",charsetUTF8), new
		 * MediaType("application", "x-www-form-urlencoded",charsetUTF8), new
		 * MediaType("text", "plain",charsetUTF8)
		 */
		MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
		jsonConverter.setSupportedMediaTypes(Arrays.asList(
				new MediaType("text", "json", charsetUTF8),
				new MediaType("application", "json", charsetUTF8)));
		jsonConverter.setObjectMapper(this.objectMapper);
		converters.add(jsonConverter);
	}

	/** 内容协商规则 **/
	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		configurer.favorPathExtension(true)
		.favorParameter(true)
		.parameterName("mediaType")
		.ignoreAcceptHeader(true)
		.useRegisteredExtensionsOnly(true)
		.mediaType("xml", MediaType.APPLICATION_XML)
		.mediaType("json", MediaType.APPLICATION_JSON)
		.defaultContentTypeStrategy(new ContentNegotiationStrategy() {
			@Override
			public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
				List<MediaType> list = new ArrayList<MediaType>();
				list.add(MediaType.TEXT_HTML);
				list.add(MediaType.TEXT_PLAIN);
				list.add(MediaType.APPLICATION_JSON);
				return list;
			}
		});
	}

	/** 添加Spring监听器 */
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 监听Locale参数的变化,用于更改本地化语言
		registry.addInterceptor(new LocaleChangeInterceptor());
	}

	@Override
	public Validator getValidator() {
		return this.validator;
	}

	/** 区域解析器 */
	@Bean
	public LocaleResolver localeResolver() {
		return new SessionLocaleResolver();
	}

	/*** 配置视图解析器 ****/
	@Bean
	public ViewResolver viewResolver() {
		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
		resolver.setViewClass(JstlView.class);
		resolver.setPrefix("/WEB-INF/jsp/");
		resolver.setSuffix(".jsp");
		return resolver;
	}

	@Bean
	public RequestToViewNameTranslator viewNameTranslator() {
		return new DefaultRequestToViewNameTranslator();
	}

	@Bean
	public MultipartResolver multipartResolver() {
		StandardServletMultipartResolver standardServletMultipartResolver = new StandardServletMultipartResolver();
		return standardServletMultipartResolver;
	}

}
